home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Audio, Video & Photo / Songbird 0.7.0 / Songbird_0.7.0_windows-i686-msvc8.exe / jsmodules / sbColumnSpecParser.jsm < prev    next >
Text File  |  2008-08-13  |  7KB  |  255 lines

  1. /*
  2. //
  3. // BEGIN SONGBIRD GPL
  4. //
  5. // This file is part of the Songbird web player.
  6. //
  7. // Copyright(c) 2005-2008 POTI, Inc.
  8. // http://songbirdnest.com
  9. //
  10. // This file may be licensed under the terms of of the
  11. // GNU General Public License Version 2 (the "GPL").
  12. //
  13. // Software distributed under the License is distributed
  14. // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
  15. // express or implied. See the GPL for the specific language
  16. // governing rights and limitations.
  17. //
  18. // You should have received a copy of the GPL along with this
  19. // program. If not, go to http://www.gnu.org/licenses/gpl.html
  20. // or write to the Free Software Foundation, Inc.,
  21. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22. //
  23. // END SONGBIRD GPL
  24. //
  25. */
  26. Components.utils.import("resource://app/jsmodules/sbProperties.jsm");
  27.  
  28. EXPORTED_SYMBOLS = ["ColumnSpecParser"];
  29.  
  30. const Cc = Components.classes;
  31. const Ci = Components.interfaces;
  32.  
  33. var Application = null;
  34.  
  35. function ColumnSpecParser(aMediaList, aPlaylist) {
  36.  
  37.   if (!Application) {
  38.     // XXXsteve FUEL is not available in jsm
  39.     Application = Cc["@mozilla.org/fuel/application;1"]
  40.                     .getService(Ci.fuelIApplication);
  41.   }
  42.  
  43.   // Our new "column spec" is a whitespace separated string that looks like
  44.   // this:
  45.   //
  46.   // "propertyID [20] [a] propertyID [40] [d]"
  47.   //
  48.   // The width and sort direction are optional.
  49.  
  50.   // Try to get this info from the following places:
  51.   //      1: "columnSpec" property on the medialist
  52.   //      2: Preference indicated by XUL "useColumnSpecPreference" attribute
  53.   //      3: "defaultColumnSpec" property on the medialist
  54.   //      4: "defaultColumnSpec" property on the medialist library
  55.   //      5: "columnSpec" property on the medialist library
  56.   //      6: XUL "columnSpec" attribute
  57.   //      7: Our last-ditch hardcoded list
  58.  
  59.   var columns;
  60.  
  61.   columns =
  62.     this._getColumnMap(aMediaList.getProperty(SBProperties.columnSpec),
  63.                        this.ORIGIN_PROPERTY);
  64.  
  65.   if (!columns.columnMap.length &&
  66.       aPlaylist &&
  67.       aPlaylist.hasAttribute("useColumnSpecPreference")) {
  68.     var pref = aPlaylist.getAttribute("useColumnSpecPreference");
  69.  
  70.     try {
  71.       if (Application.prefs.has(pref)) {
  72.         columns =
  73.             this._getColumnMap(Application.prefs.get(pref).value,
  74.                                this.ORIGIN_PREFERENCES);
  75.       }
  76.     } catch (e) {}
  77.   }
  78.  
  79.   if (!columns.columnMap.length) {
  80.     columns =
  81.       this._getColumnMap(aMediaList.getProperty(SBProperties.defaultColumnSpec),
  82.                          this.ORIGIN_MEDIALISTDEFAULT);
  83.   }
  84.  
  85.   if (!columns.columnMap.length) {
  86.     columns =
  87.       this._getColumnMap(aMediaList.library.getProperty(SBProperties.defaultColumnSpec),
  88.                          this.ORIGIN_LIBRARYDEFAULT);
  89.   }
  90.  
  91.   if (!columns.columnMap.length) {
  92.     columns =
  93.       this._getColumnMap(aMediaList.library.getProperty(SBProperties.columnSpec),
  94.                          this.ORIGIN_LIBRARY);
  95.   }
  96.  
  97.   if (!columns.columnMap.length && aPlaylist) {
  98.     columns = this._getColumnMap(aPlaylist.getAttribute("columnSpec"),
  99.                                  this.ORIGIN_ATTRIBUTE);
  100.   }
  101.  
  102.   if (!columns.columnMap.length) {
  103.     columns =
  104.       ColumnSpecParser.parseColumnSpec(SBProperties.trackName + " 229 " +
  105.                                        SBProperties.duration + " 45 " +
  106.                                        SBProperties.artistName + " 137 a " +
  107.                                        SBProperties.albumName + " 215 " +
  108.                                        SBProperties.genre + " 101 " +
  109.                                        SBProperties.rating + " 78");
  110.     this._columnSpecOrigin = this.ORIGIN_DEFAULT;
  111.   }
  112.  
  113.   if (!columns.columnMap.length) {
  114.     throw new Error("Couldn't get columnMap!");
  115.   }
  116.  
  117.   this._columns = columns;
  118. }
  119.  
  120. ColumnSpecParser.prototype = {
  121.  
  122.   _columns: null,
  123.   _columnSpecOrigin: null,
  124.  
  125.   ORIGIN_PROPERTY: 1,
  126.   ORIGIN_PREFERENCES: 2,
  127.   ORIGIN_MEDIALISTDEFAULT: 3,
  128.   ORIGIN_LIBRARYDEFAULT: 4,
  129.   ORIGIN_LIBRARY: 5,
  130.   ORIGIN_ATTRIBUTE: 6,
  131.   ORIGIN_DEFAULT: 7,
  132.  
  133.   get columnMap() {
  134.     return this._columns.columnMap;
  135.   },
  136.  
  137.   get origin() {
  138.     return this._columnSpecOrigin;
  139.   },
  140.  
  141.   get sortID() {
  142.     return this._columns.sortID;
  143.   },
  144.  
  145.   get sortIsAscending() {
  146.     return this._columns.sortIsAscending;
  147.   },
  148.  
  149.   _getColumnMap: function(columnSpec, columnSpecOrigin) {
  150.     var columns = {
  151.       columnMap: [],
  152.       sortID: null,
  153.       sortIsAscending: null
  154.     }
  155.  
  156.     if (columnSpec) {
  157.       try {
  158.         columns = ColumnSpecParser.parseColumnSpec(columnSpec);
  159.         this._columnSpecOrigin = columnSpecOrigin;
  160.       }
  161.       catch (e) {
  162.         Components.utils.reportError(e);
  163.       }
  164.     }
  165.  
  166.     return columns;
  167.   }
  168.  
  169. }
  170.  
  171. ColumnSpecParser.parseColumnSpec = function(spec) {
  172.  
  173.   var sortID;
  174.   var sortIsAscending;
  175.  
  176.   // strip leading and trailing whitespace.
  177.   var strippedSpec = spec.match(/^\s*(.*?)\s*$/);
  178.   if (!strippedSpec.length > 0)
  179.     throw new Error("RegEx failed to match string");
  180.  
  181.   // split based on whitespace.
  182.   var tokens = strippedSpec[1].split(/\s+/);
  183.  
  184.   var columns = [];
  185.   var columnIndex = -1;
  186.   var seenSort = false;
  187.  
  188.   for (var index = 0; index < tokens.length; index++) {
  189.     var token = tokens[index];
  190.     if (!token)
  191.       throw new Error("Zero-length token");
  192.  
  193.     if (isNaN(parseInt(token))) {
  194.       if (token.length == 1 && (token == "a" || token == "d")) {
  195.         // This is a sort specifier
  196.         if (columnIndex < 0) {
  197.           throw new Error("You passed in a bunk string!");
  198.         }
  199.         // Multiple sorts will be ignored!
  200.         if (!seenSort) {
  201.           var column = columns[columnIndex];
  202.           column.sort = token == "a" ? "ascending" : "descending";
  203.           seenSort = true;
  204.           sortID = column.property;
  205.           sortIsAscending = token == "a";
  206.         }
  207.       }
  208.       else {
  209.         // This is a property name.
  210.         columns[++columnIndex] = { property: token, sort: null };
  211.       }
  212.     }
  213.     else {
  214.       // This is a width specifier
  215.       if (columnIndex < 0) {
  216.         throw new Error("You passed in a bunk string!");
  217.       }
  218.       var column = columns[columnIndex];
  219.       column.width = token;
  220.     }
  221.   }
  222.  
  223.   var result = {
  224.     columnMap: columns,
  225.     sortID: sortID,
  226.     sortIsAscending: sortIsAscending
  227.   }
  228.  
  229.   return result;
  230. }
  231.  
  232. /**
  233.  * The playlist columns are no longer locked to 100% of the screen width,
  234.  * so we often need to resize all columns when appending new ones.
  235.  * 
  236.  * \param aColumnsArray Array of column objects produced by parseColumnSpec
  237.  * \param aNeededWidth Amount of room to free up in the column array
  238.  */
  239. ColumnSpecParser.reduceWidthsProportionally = function(aColumnsArray, 
  240.                                                        aNeededWidth) 
  241. {
  242.   var fullWidth = 0;
  243.   for each (var col in aColumnsArray) {
  244.     if (!col.width || col.width < 80) continue;
  245.     fullWidth += parseInt(col.width);
  246.   }
  247.   for each (var col in aColumnsArray) {
  248.     if (!col.width || col.width < 80) continue;
  249.     var fraction = parseInt(col.width)/fullWidth;
  250.     var subtract = fraction * aNeededWidth;
  251.     // Round down, since it is better to be too small than to overflow
  252.     // and require a scroll bar
  253.     col.width = Math.floor(parseInt(col.width) - subtract);
  254.   }
  255. }